home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / programm.ing / cpp114.zoo / src / pound.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-30  |  8.8 KB  |  400 lines

  1.  
  2. /*---------------------------------------------------------------------*\
  3. |                                    |
  4. | CPP -- a stand-alone C preprocessor                    |
  5. | Copyright (c) 1993-95 Hacker Ltd.        Author: Scott Bigham    |
  6. |                                    |
  7. | Permission is granted to anyone to use this software for any purpose    |
  8. | on any computer system, and to redistribute it freely, with the    |
  9. | following restrictions:                        |
  10. | - No charge may be made other than reasonable charges for repro-    |
  11. |     duction.                                |
  12. | - Modified versions must be clearly marked as such.            |
  13. | - The author is not responsible for any harmful consequences of    |
  14. |     using this software, even if they result from defects therein.    |
  15. |                                    |
  16. | pound.c -- handle preprocessor directives                |
  17. \*---------------------------------------------------------------------*/
  18.  
  19. #include <stddef.h>
  20. #include <string.h>
  21. #include <stdlib.h>
  22. #include <errno.h>
  23. #include <ctype.h>
  24. #include "global.h"
  25.  
  26. #define IF_STACK_SIZE 10
  27. #define N_DIRS nelems(d_table)
  28. #define IF_STATE (if_sp[-1])
  29.  
  30. #define COND_FALSE    0
  31. #define COND_ELSE_SEEN    4
  32. #define COND_DONE_TRUE    8
  33.  
  34. /* The hash values for the directives depend on the prevailing int size.
  35.    Make sure that __MSHORT__ is #define'd if sizeof(int) == 2. */
  36. #ifdef __MSHORT__
  37. #define    POUND_DEFINE    782
  38. #define    POUND_UNDEF    200
  39. #define    POUND_INCLUDE    713
  40. #define    POUND_IF    645
  41. #define    POUND_IFDEF    362
  42. #define    POUND_IFNDEF    1032
  43. #define    POUND_ELSE    559
  44. #define    POUND_ELIF    230
  45. #define    POUND_ENDIF    750
  46. #define    POUND_LINE    675
  47. #define    POUND_ERROR    679
  48. #define    POUND_PRAGMA    1039
  49. #define    POUND_EMPTY    0
  50. #else
  51. #define    POUND_DEFINE    252
  52. #define    POUND_UNDEF    383
  53. #define    POUND_INCLUDE    386
  54. #define    POUND_IF    645
  55. #define    POUND_IFDEF    324
  56. #define    POUND_IFNDEF    424
  57. #define    POUND_ELSE    793
  58. #define    POUND_ELIF    464
  59. #define    POUND_ENDIF    1017
  60. #define    POUND_LINE    713
  61. #define    POUND_ERROR    799
  62. #define    POUND_PRAGMA    864
  63. #define    POUND_EMPTY    0
  64. #endif
  65.  
  66.  
  67. static int *if_stack, if_stack_size;
  68. int *if_sp;
  69.  
  70. extern void do_include __PROTO((void));
  71. extern void do_define __PROTO((void));
  72. extern void do_undefine __PROTO((void));
  73.  
  74. /* set up the conditional-compile stack */
  75. void cond_setup()
  76. {
  77.   if_sp = if_stack = (int *)mallok((if_stack_size = IF_STACK_SIZE) * sizeof (int));
  78.  
  79.   *if_sp++ = COND_TRUE;
  80. }
  81.  
  82. /*
  83.    endif_check() -- see if there are states left on the stack; each
  84.    corresponds to a missing #endif
  85. */
  86. void endif_check()
  87. {
  88.   int i;
  89.  
  90.   i = (int)(if_sp - if_stack) - 1;
  91.   if (i) {
  92.     while (i--)
  93.       error("missing #endif");
  94.   }
  95.   if_sp = if_stack;
  96.   *if_sp++ = COND_TRUE;
  97. }
  98.  
  99. /* cond_shutdown() -- free the conditional-compile stack() */
  100. void cond_shutdown()
  101. {
  102.   free(if_stack);
  103. }
  104.  
  105. /* cond_push() -- push a conditional-compile state onto the stack */
  106. static void cond_push(s)
  107.   int s;
  108. {
  109.   if (if_sp - if_stack >= if_stack_size) {
  110.     ptrdiff_t dp;
  111.  
  112.     dp = if_sp - if_stack;
  113.     if_stack = reallok(if_stack, (if_stack_size *= 2) * sizeof (int));
  114.  
  115.     if_sp = if_stack + dp;
  116.   }
  117.   *if_sp++ = s;
  118. }
  119.  
  120. /* cond_pop() -- remove a conditional-compile state from the stack */
  121. static void cond_pop()
  122. {
  123.   if (if_sp - if_stack <= 1)
  124.     error("unmatched #endif");
  125.   else
  126.     if_sp--;
  127. }
  128.  
  129. /* do_if() -- handle an #if directive */
  130. static void do_if()
  131. {
  132.   cond_push(!cond_true()? COND_NESTED :
  133.         if_expr()? COND_TRUE | COND_DONE_TRUE :
  134.         COND_FALSE
  135.   );
  136. }
  137.  
  138. /* do_ifdef() -- handle an #ifdef directive */
  139. static void do_ifdef()
  140. {
  141.   TokenP T;
  142.  
  143.   T = _one_token();
  144.   if (T->type != ID)
  145.     error("argument \"%s\" to #ifdef is not an identifier", token_txt(T));
  146.   else {
  147.     cond_push(!cond_true()? COND_NESTED :
  148.           lookup(token_txt(T), T->hashval) ? COND_TRUE | COND_DONE_TRUE :
  149.           COND_FALSE
  150.     );
  151.   }
  152.   free_token(T);
  153.   T = _one_token();
  154.   if (T->type != EOL)
  155.     warning("garbage after #ifdef");
  156.   free_token(T);
  157. }
  158.  
  159. /* do_ifndef() -- handle an #ifndef directive */
  160. static void do_ifndef()
  161. {
  162.   TokenP T;
  163.  
  164.   T = _one_token();
  165.   if (T->type != ID)
  166.     error("argument \"%s\" to #ifndef is not an identifier", token_txt(T));
  167.   else {
  168.     cond_push(!cond_true()? COND_NESTED :
  169.           lookup(token_txt(T), T->hashval) ? COND_FALSE :
  170.           COND_TRUE | COND_DONE_TRUE
  171.     );
  172.   }
  173.   free_token(T);
  174.   T = _one_token();
  175.   if (T->type != EOL)
  176.     warning("garbage after #ifndef");
  177.   free_token(T);
  178. }
  179.  
  180. /* do_else() -- handle an #else directive */
  181. static void do_else()
  182. {
  183.   TokenP T;
  184.  
  185.   if (IF_STATE & COND_ELSE_SEEN)
  186.     error("#else after #else");
  187.   if (IF_STATE & COND_DONE_TRUE)
  188.     IF_STATE &= (~COND_TRUE);
  189.   else
  190.     IF_STATE |= (COND_TRUE | COND_DONE_TRUE);
  191.   T = _one_token();
  192.   if (T->type != EOL)
  193.     warning("garbage after #else");
  194.   free_token(T);
  195. }
  196.  
  197. /* do_elif() -- handle an #elif directive */
  198. static void do_elif()
  199. {
  200.   if (IF_STATE & COND_ELSE_SEEN)
  201.     error("#elif after #else");
  202.   if (IF_STATE & COND_DONE_TRUE)
  203.     IF_STATE &= (~COND_TRUE);
  204.   else if (if_expr())
  205.     IF_STATE |= (COND_TRUE | COND_DONE_TRUE);
  206.   else
  207.     IF_STATE &= (~COND_TRUE);
  208. }
  209.  
  210. /* do_endif() -- handle an #endif directive */
  211. static void do_endif()
  212. {
  213.   TokenP T;
  214.  
  215.   cond_pop();
  216.   T = _one_token();
  217.   if (T->type != EOL)
  218.     warning("garbage after #endif");
  219.   free_token(T);
  220. }
  221.  
  222. /* do_line() -- handle a #line directive */
  223. static void do_line()
  224. {
  225.   TokenP Tn, Tf;
  226.   int l;
  227.  
  228.   _tokenize_line();
  229.   Tn = exp_token();
  230.   if (Tn->type != NUMBER) {
  231.     error("malformed number \"%s\" in #line directive", token_txt(Tn));
  232.     free_token(Tn);
  233.     return;
  234.   }
  235.   Tf = exp_token();
  236.   if (Tf->type != STR_CON && Tf->type != EOL) {
  237.     error("malformed filename \"%s\" in #line directive", token_txt(Tf));
  238.     free_token(Tn);
  239.     free_token(Tf);
  240.     return;
  241.   }
  242.   if (Tf->type == STR_CON) {
  243.     l = strlen(token_txt(Tf)) - 2;
  244.     free(cur_file);
  245.     cur_file = mallok(l + 1);
  246.     strncpy(cur_file, token_txt(Tf) + 1, l);
  247.     cur_file[l] = '\0';
  248.     free_token(Tf);
  249.     Tf = exp_token();
  250.     if (Tf->type != EOL)
  251.       error("garbage after #line");
  252.     free_token(Tf);
  253.   }
  254.   this_line = next_line = Tn->val;
  255.   sync_line(0);
  256.   free_token(Tn);
  257. }
  258.  
  259. /* do_error() -- handle an #error directive */
  260. static void do_error()
  261. {
  262.   error("%s", rest_of_line());
  263. }
  264.  
  265. /* write_pragma_text() -- write a token contaning the text |s| directly
  266.    to the output file
  267. */
  268. static void write_pragma_text(s)
  269.   const char *s;
  270. {
  271.   register TokenP T = mk_printable(s);
  272.  
  273.   print_token(T);
  274.   free_token(T);
  275. }
  276.  
  277. /* do_pragma() -- handle a #pragma directive */
  278. static void do_pragma()
  279. {
  280.   TokenP T = _one_token();
  281.   int recognized = 0;
  282.  
  283.   if (T->type == EOL) {
  284.     warning("empty #pragma directive");
  285.     free_token(T);
  286.     return;
  287.   }
  288.   if (in_config_file) {
  289.     /* pragmas that are enabled only in config file */
  290.     if (streq(token_txt(T), "CPP_cmdline_arg")) {
  291.       char *s = rest_of_line();
  292.  
  293.       recognized = 1;
  294.       while (isspace(*s))
  295.     s++;
  296.       if (*s == '-')
  297.     do_cmdline_arg(s);
  298.       else
  299.     error("invalid cmdline arg \"%s\" in #pragma CPP_cmdline_arg", s);
  300.     } else if (streq(token_txt(T), "CPP_delayed")) {
  301.       recognized = 1;
  302.       if (Argc_end != 0)
  303.     error("#pragma CPP_delayed cannot be repeated");
  304.       else
  305.     do_all_cmdline_args();
  306.     }
  307.   }
  308.   if (fluff_mode && streq(token_txt(T), "fluff")) {
  309.     /* pragmas for use with fluff */
  310.     TokenP T0 = _one_token();
  311.  
  312.     recognized = 1;
  313.     if (T0->type == EOL) {
  314.       error("empty `#pragma fluff' directive");
  315.     } else if (streq(token_txt(T0), "varargs")) {
  316.       write_pragma_text("__FLUFF_varargs");
  317.       write_pragma_text("\n");
  318.       last_line++;
  319.     } else {
  320.       error("invalid `#pragma fluff directive \"%s\"", token_txt(T0));
  321.     }
  322.     free_token(T0);
  323.   }
  324.   if (!recognized && w_pragma) {
  325.     warning("unrecognized #pragma directive:  '%s'", token_txt(T));
  326.   }
  327.   free_token(T);
  328.   return;
  329. }
  330.  
  331. /*
  332.    directive() -- perform the directive on the current input line
  333. */
  334. void directive()
  335. {
  336.   TokenP T;
  337.  
  338.   T = _one_token();
  339.   if (T->type == EOL) {
  340.     free_token(T);
  341.     return;
  342.   }
  343.   switch (T->hashval + token_txt(T)[0]) {
  344.   case POUND_DEFINE:
  345.     /* 1/30/95 sb -- To accommodate the unspeakably obnoxious GCC-style
  346.        implicit newlines in string literals, we have to tokenize the
  347.        entire line even inside a false #if, just in case there's a
  348.        wrapped string in it.  Grmbl... */
  349.     if (cond_true())
  350.       do_define();
  351.     else if (gcc_strings)
  352.       _tokenize_line();
  353.     break;
  354.   case POUND_UNDEF:
  355.     if (cond_true())
  356.       do_undefine();
  357.     break;
  358.   case POUND_INCLUDE:
  359.     if (cond_true())
  360.       do_include();
  361.     break;
  362.   case POUND_IF:
  363.     do_if();
  364.     break;
  365.   case POUND_IFDEF:
  366.     do_ifdef();
  367.     break;
  368.   case POUND_IFNDEF:
  369.     do_ifndef();
  370.     break;
  371.   case POUND_ELSE:
  372.     do_else();
  373.     break;
  374.   case POUND_ELIF:
  375.     do_elif();
  376.     break;
  377.   case POUND_ENDIF:
  378.     do_endif();
  379.     break;
  380.   case POUND_LINE:
  381.     if (cond_true())
  382.       do_line();
  383.     break;
  384.   case POUND_ERROR:
  385.     if (cond_true())
  386.       do_error();
  387.     break;
  388.   case POUND_PRAGMA:
  389.     if (cond_true())
  390.       do_pragma();
  391.     break;
  392.   case POUND_EMPTY:
  393.     break;
  394.   default:
  395.     fatal("unrecognized preprocessor directive #%s", token_txt(T));
  396.   }
  397.   free_token(T);
  398.   flush_line();
  399. }
  400.